home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
FishMarket 1.0
/
FishMarket v1.0.iso
/
fishies
/
476-500
/
disk_500
/
wiconify
/
wiconify-source.lzh
/
Source
/
wLayout.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-04-19
|
11KB
|
396 lines
/*
* WICONIFY A utility that allows you to iconify any Intuition window
* on any screen, and to open WB windows on any screen.
*
* wLayout.c Handles placement and rearranging of icons.
*
* Copyright 1990 by Davide P. Cervone, all rights reserved.
* You may use this code, provided this copyright notice is kept intact.
*/
#include "wHandler.h"
static UWORD Xmax; /* maximum number of columns */
static UWORD Ymax; /* maximum number of rows */
#define XOFFSET 80 /* distance between icons */
#define YOFFSET 34 /* distance between icons */
#define XSTART 20 /* Starting X position */
#define YSTART 28 /* Starting Y position (from bottom) */
#define YDIFF 10 /* vertical offset for odd rows */
#define XMAX 32 /* maximum icons in x direction */
#define YMAX 32 /* maximum icons in y direction */
#define GADGICON ((WICONREF *)theGadget->UserData)
/*
* GetPosition()
*
* Get the icon of the gadget (UserData points to the icon)
* Get the X position of the gadget normalized for varrying widths of icons
* Find the nearest X column position by dividing by the column width
* Get the Y position of the gadget normalized by height,with 0 at the bottom
* Offset the Y position for odd rows
* Get two different Y row positions (it may cover two positions vertically
* if it is not exactly placed on the grid)
*/
static void GetPosition(theGadget,X,Y1,Y2)
struct Gadget *theGadget;
WORD *X,*Y1,*Y2;
{
WICONREF *theIcon = (WICONREF *)theGadget->UserData;
*X = theGadget->LeftEdge + (theGadget->Width - ICONWIDTH) / 2;
*X = (*X - XSTART + (XOFFSET/2)) / XOFFSET;
*Y2 = theIcon->Screen->BackDrop->Height - theGadget->TopEdge;
*Y2 = *Y2 - (theGadget->Height - ICONHEIGHT) - YSTART;
if ((*X & 1) == 0) *Y2 -= YDIFF;
*Y1 = (*Y2 + (YOFFSET /4)) / YOFFSET;
*Y2 = (*Y2 + (YOFFSET*3/4)) / YOFFSET;
}
/*
* GetPositionArray()
*
* Calculate the maximum number of rows and columns, clip to the array size
* Clear the position array
* While there are gadgets to work with
* Get the gadget's position
* Add it into the array
* Add its second position into the array unless we are only conncered
* with where the gadgets "should" be (ie, snapped to the grid)
* Increment the gadget count if the gadget can be moved
* Go on to the next gadget
* Return the number of gadgets counted
*/
static UWORD GetPositionArray(PosArray,theScreen,Snapped)
ULONG PosArray[];
WSCREEN *theScreen;
int Snapped;
{
struct Gadget *theGadget = theScreen->BackDrop->FirstGadget;
WORD X,Y1,Y2;
UWORD count = 0;
Xmax = (theScreen->BackDrop->Width / XOFFSET);
Ymax = (theScreen->BackDrop->Height - YSTART) / YOFFSET;
if (Xmax > XMAX) Xmax = XMAX;
if (Ymax > YMAX) Ymax = YMAX;
for (Y1 = 0; Y1 < YMAX; Y1++) PosArray[Y1] = 0;
while(theGadget)
{
GetPosition(theGadget,&X,&Y1,&Y2);
PosArray[Y1] |= (1 << X);
if (Snapped == FALSE) PosArray[Y2] |= (1 << X);
if ((GADGICON->Icon.Flags & (WI_NOORGANIZE | WI_LOCKED)) == 0) count++;
theGadget = theGadget->NextGadget;
}
return(count);
}
/*
* ValidPosition()
*
* Check the row and column position to make sure it is on screen
* If not, move it one the screen area
*/
static void ValidPosition(X,Y)
WORD *X,*Y;
{
if (*X < 0) *X = 0;
if (*Y < 0) *Y = 0;
if (*X >= Xmax) *X = Xmax - 1;
if (*Y > Ymax) *Y = Ymax;
}
/*
* Offsets for which positions to check when looking for the nearest
* grid location (used when two icons overlap). There are separate
* choices for even and odd rows
*/
#define DCOUNT 8
static WORD dx[2][DCOUNT] =
{
{ 0, -1, 1, -1, 1, -1, 1, 0},
{ 0, -1, 1, -1, 1, 0, -1, 1}
};
static WORD dy[2][DCOUNT] =
{
{-1, 0, 0, -1, -1, 1, 1, 1},
{-1, -1, -1, 0, 0, 1, 1, 1}
};
/*
* FindClosePosition()
*
* Check that the icon position is legal
* If the gadget overlaps another one already in the array
* Use the correct table for even or odd columns
* While there are more positions to try
* Get the new position for the given position
* Make sure the position is within the screen
* If the location is free
* Save the new position and indicate that we're done
* Indicate that the position is OK
* Return a statment about whether there was a closeby place free
*/
static int FindClosePosition(PosArray,X,Y,Y2)
ULONG PosArray[];
WORD *X,*Y,*Y2;
{
int Found = FALSE;
short i,j;
WORD Xt,Yt;
ValidPosition(X,Y);
if ((PosArray[*Y] | PosArray[*Y2]) & (1 << *X))
{
j = *X & 1;
for (i=0; i<DCOUNT && Found == FALSE; i++)
{
Xt = *X + dx[j][i];
Yt = *Y + dy[j][i];
ValidPosition(&Xt,&Yt);
if ((PosArray[Yt] & (1 << Xt)) == 0)
{
Found = TRUE;
*X = Xt; *Y = Yt;
}
}
} else Found = TRUE;
return(Found);
}
/*
* GetNewPosition()
*
* Create a mask with 1's in all the valid column positions
* Look for the first row with an empty slot
* If we are past the end of the array,
* Set the position to the origin (bail out)
* Otherwise
* Look through the row from left to right for the first location
* Verify that what we found really IS an OK position
*/
static void GetNewPosition(PosArray,X,Y)
ULONG PosArray[];
WORD *X,*Y;
{
ULONG Xmask = (1 << Xmax) - 1;
for (*Y = 0; *Y < Ymax && (PosArray[*Y] & Xmask) == Xmask; (*Y)++);
if (*Y >= Ymax)
*Y = *X = 0;
else
for (*X = 0, Xmask = 1; PosArray[*Y] & Xmask; (*X)++, Xmask <<= 1);
ValidPosition(X,Y);
}
/*
* SetPosition()
*
* If the icon is not locked in place
* Get the current X and Y (in pixels) for the icon's new position
* (centered the icon horizontally)
* If the gadget's current location is different
* Set the gadgets's new position
* If the icon is supposed to get movement reports, report the change
*/
static void SetPosition(theGadget,X,Y)
struct Gadget *theGadget;
WORD X,Y;
{
WICONREF *theIcon = (WICONREF *)theGadget->UserData;
if ((theIcon->Icon.Flags & WI_LOCKED) == FALSE)
{
Y = theIcon->Screen->BackDrop->Height - YSTART - (Y * YOFFSET);
if ((X & 1) == 0) Y -= YDIFF;
X = (X * XOFFSET) + XSTART - (theGadget->Width - ICONWIDTH) / 2;
Y -= theGadget->Height - ICONHEIGHT;
if (theGadget->LeftEdge != X || theGadget->TopEdge != Y)
{
theGadget->LeftEdge = X; theIcon->Icon.x = X;
theGadget->TopEdge = Y; theIcon->Icon.y = Y;
if (theIcon->Icon.Report & WI_REPORTMOVED)
ReportEvent(WI_REPORTMOVED,theIcon);
}
}
}
/*
* InitPosition()
*
* Get the position of the gadget and save it
* Get the position array for the screen (do not snap icons to the grid)
* If the gadget already has a position
* If we can't find a closeby position get the first available one
* If the position changed, set the new position
* Otherwise
* Get the first available position
* Set the gadget's position
*/
void InitPosition(theGadget)
struct Gadget *theGadget;
{
WICONREF *theIcon = (WICONREF *)theGadget->UserData;
ULONG PosArray[YMAX];
WORD X,Y,Y2;
WORD OldX,OldY;
GetPosition(theGadget,&X,&Y,&Y2); OldX = X; OldY = Y;
GetPositionArray(PosArray,theIcon->Screen,FALSE);
if (theGadget->LeftEdge || theGadget->TopEdge)
{
if (!FindClosePosition(PosArray,&X,&Y,&Y2))
GetNewPosition(PosArray,&X,&Y);
if (X != OldX || Y != OldY) SetPosition(theGadget,X,Y);
} else {
GetNewPosition(PosArray,&X,&Y);
SetPosition(theGadget,X,Y);
}
}
/*
* CleanUpIcons()
*
* Get the positions of all icons on the screen (no snapping)
* Clear the temporary array
* Start with the first gadget on the screen
* If there are selected gadgets
* Add all the unselected gadgets to the temporary array
* Start with the first selected gadget
* While there are more gadgets to handle
* Get the gadget's position and validate it
* If the icon can be moved
* If the icon's position is already in use
* Find the closest place, or the next available one
* Set the gadget's position
* Add the gadget to the arrays
* If gadgets are selected, go on to the next selected one
* Otherwise go on to the next one
*/
void CleanUpIcons(theScreen)
WSCREEN *theScreen;
{
ULONG PosArray[YMAX];
ULONG TmpArray[YMAX];
WORD X,Y,Y2;
short Selected;
struct wGadget *theGadget;
Forbid();
GetPositionArray(PosArray,theScreen,FALSE);
for (Y = 0; Y < YMAX; Y++) TmpArray[Y] = 0;
theGadget = (struct wGadget *)theScreen->BackDrop->FirstGadget;
Selected = (theScreen->Selected != NULL);
if (Selected)
{
while (theGadget)
{
if ((theGadget->Gadget.Flags & SELECTED) == FALSE)
{
GetPosition(theGadget,&X,&Y,&Y2);
TmpArray[Y] |= (1 << X);
TmpArray[Y2] |= (1 << X);
}
theGadget = (struct wGadget *)theGadget->Gadget.NextGadget;
}
theGadget = theScreen->Selected;
}
while (theGadget)
{
GetPosition(theGadget,&X,&Y,&Y2);
ValidPosition(&X,&Y);
if ((GADGETICON->Icon.Flags & (WI_NOORGANIZE| WI_LOCKED)) == FALSE)
{
if ((TmpArray[Y] | TmpArray[Y2]) & (1 << X))
if (!FindClosePosition(PosArray,&X,&Y,&Y2))
GetNewPosition(PosArray,&X,&Y);
SetPosition(theGadget,X,Y);
}
TmpArray[Y] |= (1 << X);
PosArray[Y] |= (1 << X);
if (Selected)
theGadget = theGadget->NextSelect;
else
theGadget = (struct wGadget *)theGadget->Gadget.NextGadget;
}
Permit();
}
/*
* OrganizeIcons()
*
* Start with the first gadget on the screen
* Count the gadgets and get the position array
* Find the highest row and the right-most column in that row needed
* in order to store that many icons
* Clear the temporary array
* While there are gadgets to check
* Get the gadget's position and validate it
* If the gadget can be moved
* If the icon's position is in use, or if it is outside the final
* block of organized icons, get a new position for the gadget
* Set the gadgets position
* Save the icon's position in both arrays
* Move on to the next gadget
*/
void OrganizeIcons(theScreen)
WSCREEN *theScreen;
{
ULONG PosArray[YMAX];
ULONG TmpArray[YMAX];
WORD X,Y,Y2;
WORD RightX, TopY;
UWORD count;
struct Gadget *theGadget;
Forbid();
theGadget = theScreen->BackDrop->FirstGadget;
count = GetPositionArray(PosArray,theScreen,TRUE);
TopY = count / Xmax;
RightX = count - TopY * Xmax;
for (Y = 0; Y < YMAX; Y++) TmpArray[Y] = 0;
while (theGadget)
{
GetPosition(theGadget,&X,&Y,&Y2);
ValidPosition(&X,&Y);
if ((GADGICON->Icon.Flags & (WI_NOORGANIZE| WI_LOCKED)) == FALSE)
{
if ((TmpArray[Y] & (1 << X)) || Y > TopY || (Y == TopY && X >= RightX))
GetNewPosition(PosArray,&X,&Y);
SetPosition(theGadget,X,Y);
}
PosArray[Y] |= (1 << X);
TmpArray[Y] |= (1 << X);
theGadget = theGadget->NextGadget;
}
Permit();
}